<template>
  <BigScreen />
  <div class="container" ref="container"></div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import BigScreen from "@/components/BigScreen.vue";
// 导入threejs
import * as THREE from "three";
import gsap from "gsap";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
//变换控制器
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
// 导入lil.gui
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
// 导入hdr加载器
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
// 导入gltf加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 导入draco解码器
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
//效果合成器
// 导入后期效果合成器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";

// three框架本身自带效果
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass";

import eventHub from "@/utils/eventHub";

//创建gui对象
// const gui = new GUI();
// 创建场景
const scene = new THREE.Scene();
const cubeTextureLoader = new THREE.CubeTextureLoader().setPath("./textures/skybox/");
const textureCube = cubeTextureLoader.load([
  // "1.jpg",
  // "2.jpg",
  // "3.jpg",
  // "4.jpg",
  // "5.jpg",
  // "6.jpg",
  "/01/px.jpg",
  "/01/nx.jpg",
  "/01/py.jpg",
  "/01/ny.jpg",
  "/01/pz.jpg",
  "/01/nz.jpg",
]);


scene.background = textureCube;
// scene.environment = textureCube;
// 创建相机
const camera = new THREE.PerspectiveCamera(
  45, // 视角
  window.innerWidth / window.innerHeight, // 宽高比
  1, // 近平面 过低导致模型缩放翻转模糊
  10000 // 远平面
);
//设置机位
camera.position.x = -150;
camera.position.y = 40;
camera.position.z = 500;
// camera.position.x = 0;
// camera.position.y = 1000;
// camera.position.z = 0;
// camera.lookAt(0, -50, 0);

//添加环境光
const light = new THREE.AmbientLight(0xffffff, 2);
scene.add(light);
// const pointLight = new THREE.PointLight(0xffffff, 100);
// camera.add(pointLight);
// 添加平行光
let directionalLight = new THREE.DirectionalLight(0xffffff, 4);
directionalLight.position.set(150, 1200, 450);
// 默认平行光的目标是原点
directionalLight.target.position.set(0, 0, 0);
// 设置光投射阴影
directionalLight.castShadow = true;
// 设置光的投射范围
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
//阴影半径
directionalLight.shadow.radius = 5;
//设置阴影偏移 修复阴影失真  这句很重要
directionalLight.shadow.bias = -0.0005;
directionalLight.shadow.camera.left = -100;
directionalLight.shadow.camera.right = 100;
directionalLight.shadow.camera.top = 100;
directionalLight.shadow.camera.bottom = -100;
directionalLight.shadow.camera.near = 1;
directionalLight.shadow.camera.far = 2000;
scene.add(directionalLight);



// 添加平行光辅助器
// let directionalLightHelper = new THREE.DirectionalLightHelper(
//   directionalLight
// );
// scene.add(directionalLightHelper);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true, // 开启抗锯齿
  // 开启深度缓存
  // logarithmicDepthBuffer: true,
  alpha: true,
  // 开启阴影
  shadowMap: true,
});
// renderer.toneMapping = THREE.ACESFilmicToneMapping;
// renderer.toneMappingExposure = 1;
renderer.gammaOutput = false;
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);

const renderScene = new RenderPass(scene, camera);
const bloomPass = new UnrealBloomPass(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  2,
  0.4,
  0.85
);
bloomPass.threshold = 0;
bloomPass.strength = 0.07;
bloomPass.radius = 0;
const outputPass = new OutputPass();
// 抗锯齿
const smaaPass = new SMAAPass();

const size = renderer.getDrawingBufferSize(new THREE.Vector2());
const renderTarget = new THREE.WebGLRenderTarget(size.width, size.height, {
  samples: 4,
  type: THREE.HalfFloatType,
});
const composer = new EffectComposer(renderer, renderTarget);
composer.addPass(renderScene);
composer.addPass(bloomPass);
composer.addPass(outputPass);
composer.addPass(smaaPass);

//3D渲染容器
const container = ref(null);

//uuid 生成器
const { v4: uuidv4 } = require("uuid");
// 实例化加载器gltf
const gltfLoader = new GLTFLoader();
//物体列表
//主场景物体
const mainArr = [];
//科创大厦楼层
const kcArr = [];
//所有物体
const allArr = [];

//当前检测对象
let currentArr = [];
let isMain = true;
let isTagPostion = false;
let isOpenLuminous = false;

function showAllObject(isShow) {
  allArr.forEach((item) => {
    if (isShow) {
      item.visible = true;
    } else {
      item.visible = false;
    }
  })
}

function showFloor(floorName) {
  var fName = 'Floor@' + floorName;
  let object = scene.getObjectByName(fName);
  if (object) {
    object.visible = true;
    currentArr = [];
    object.traverse((child) => {
      child.visible = true;
      currentArr.push(child);
    })
  }
  //
  isOpenLuminous = false;
  //模拟调整到楼层
  goFloorCamera();
}



//方法区
function goMainCamera() {
  isMain = true;
  gsap.to(camera.position, {
    duration: 1.2,
    x: -150,
    y: 40,
    z: 500,
  });
  //取消辉光
  closeLuminous();
}

function goFloorsCamera() {
  gsap.to(camera.position, {
    duration: 1.2,
    x: 0,
    z: 250,
  });
}

function goFloorCamera() {
  gsap.to(camera.position, {
    duration: 0.8,
    x: 0,
    y: 70,
    z: 0,
  });
}

function tagPostion() {
  controls.enabled = false;
  //进入标点模式
  isTagPostion = true;
  //开启物体控制器
  objControls.visible = false;
  //关闭辉光
  isOpenLuminous = false;
  //所有物体添加检测
  currentArr = allArr;
  goMainCamera();
}

function closeLuminous() {
  if (!isOpenLuminous) {
    return;
  }
  // 将所有物体体的自发光强度恢复为默认值
  allArr.forEach((cube) => {
    if (cube.isMesh) {
      cube.material.emissive = new THREE.Color(0x000000); // 将自发光颜色设置为黑色
      cube.material.emissiveIntensity = 0; // 将自发光强度设置为0
    }
  });
}
function luminous(object) {
  if (isOpenLuminous) {
    if (isMain) {
      // console.log('父类是：', object.parent.name)
      let parnet = scene.getObjectByName(object.parent.name);
      //遍历所有子节点添加自发光
      parnet.traverse(function (child) {
        if (child.isMesh && child.name.includes('luminous@')) {
          child.material.emissive = new THREE.Color(0x71faff); // 设置为绿色
          // 设置自发光强度
          child.material.emissiveIntensity = 80; // 设置强度为1.0
        }
      });
    } else {
      object.material.emissive = new THREE.Color(0x71faff); // 设置为绿色
      // 设置自发光强度
      object.material.emissiveIntensity = 80; // 设置强度为1.0
    }

  }
}

function clickRayObject(obj) {
  if (isMain && !isTagPostion) {
    // 点击主楼
    isMain = false;
    closeLuminous();
    console.log('点击了', obj);
    var buildName = obj.object.parent.name;
    let parnet = scene.getObjectByName(buildName);
    currentArr = [];
    //遍历所有子节点 将相关楼层的检测点放入到辉光检测列表中
    var buildPix = buildName.replace("Build@", "");
    console.log('主建筑名称：', buildPix);
    parnet.traverse(function (child) {
      if (child.isMesh && child.name.startsWith(buildPix)) {
        currentArr.push(child);
      }
    });
    //跳转到主楼，同时切换摄像机位置信息
    goFloorsCamera();
  } else if (!isMain && !isTagPostion) {
    //点击了楼层 进入到楼层
    //隐藏所有物体
    showAllObject(false);
    //显示具体楼层
    showFloor('KC-F-18');

  } else if (isMain && isTagPostion) {
    console.log('点击物体为：', obj.object.name);
    var position = obj.point.clone();
    createSpriteTag(position);
  } else {
    //点击了楼层
  }
}

const spriteMap = new THREE.TextureLoader().load("/textures/icon/fj_icon.png");
spriteMap.encoding = THREE.LinearEncoding;
const spriteMaterial = new THREE.SpriteMaterial({ map: spriteMap, sizeAttenuation: false });
//颜色失真
spriteMaterial.map.colorSpace = 'srgb';
const tags = [];
function createSpriteTag(position) {
  if (!isTagPostion) {
    return;
  }
  console.log('点击物体位置坐标为：', position);
  const sprite = new THREE.Sprite(spriteMaterial);
  //设置位置 
  //将精灵位置设置为鼠标点击的世界坐标点
  sprite.position.set(-100, 20, 132);
  sprite.scale.set(0.03, 0.03, 1);
  if (tags.length > 0) {
    return;
  }
  scene.add(sprite);
  tags.push(sprite);
  objControls.attach(sprite);
}

// 加载模型
gltfLoader.load(
  // 模型路径
  "./model/scene.glb",
  // 加载完成回调
  (gltf) => {
    console.log(gltf);
    gltf.scene.traverse(function (child) {
      if (child.name.includes("Build@")) {
        mainArr.push(child);
        console.log(mainArr);
      }
      if (child.isMesh) {
        // 关闭自发光
        // child.material.emissive = new THREE.Color(0x000000); // 将自发光颜色设置为黑色
        // child.material.emissiveIntensity = 0; // 将自发光强度设置为0
        child.castShadow = true;
        child.receiveShadow = true;
        let uuid = uuidv4();
        // 取出原材质
        const originalMaterial = child.material;
        // 克隆材质并修改参数
        const newMaterial = originalMaterial.clone();
        //重设材质ID和名称
        newMaterial.uuid = uuid;
        newMaterial.name = uuid;
        child.material = newMaterial;
        //所有物体
        allArr.push(child);
      }
    });
    var model = gltf.scene;
    scene.add(model);
  }
);


// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼的惯性
// controls.enableDamping = true;
controls.target = new THREE.Vector3(0, 50, 0);
// 变换控制器
const objControls = new TransformControls(camera, renderer.domElement);
// objControls.addEventListener("change", animate);
// 监听拖动事件，当拖动物体时候，禁用轨道控制器
// objControls.addEventListener("dragging-changed", function (event) {
//   controls.enabled = !event.value;
// });
objControls.addEventListener("change", () => {
  objControls.object.position.y = 20;
});
scene.add(objControls);
// 渲染函数
function animate() {
  controls.update();
  // updateCameraRotation();
  //渲染动画
  requestAnimationFrame(animate);
  //渲染场景
  // renderer.render(scene, camera);
  composer.render();
};

onMounted(() => {
  //将渲染后的canvas 添加到dom中
  container.value.appendChild(renderer.domElement);
  animate();
  //初始化场景 开启辉光 主楼开始检测
  isOpenLuminous = true;
  currentArr = mainArr;
  // 创建投射光线对象
  const raycaster = new THREE.Raycaster();
  raycaster.params.Line.threshold = 0.05;

  // 鼠标的位置对象
  const mouse = new THREE.Vector2();
  // 监听鼠标的位置
  window.addEventListener("mousemove", (event) => {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
    raycaster.setFromCamera(mouse, camera);
    // 将所有立方体的自发光强度恢复为默认值
    closeLuminous();
    let result = raycaster.intersectObjects(currentArr, true);
    console.log(result);
    if (result.length > 0) {
      let object = result[0].object;
      luminous(object);
      // if (isMain) {
      //   //首页默认将主楼高亮
      //   let object = scene.getObjectByName("KC");
      //   if (object) {
      //     luminous(object);
      //   }
      // } else {
      //   let object = result[0].object;
      //   luminous(object);
      // }
    }
  });
  // 事件监听
  window.addEventListener("click", (event) => {
    //   console.log(event);
    //   对时间对象进行加工
    // event.mesh = this;
    // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
    //通过摄像机和鼠标位置更新射线
    raycaster.setFromCamera(mouse, camera);
    //进行检测
    let result = raycaster.intersectObjects(currentArr, true);
    // console.log(result);
    if (result.length > 0) {
      let object = result[0];
      //点击了射线物体
      clickRayObject(object);
    }
  });

  // 监听屏幕大小改变的变化，设置渲染的尺寸
  window.addEventListener("resize", () => {
    //   console.log("resize");
    // 更新摄像头
    camera.aspect = window.innerWidth / window.innerHeight;
    //   更新摄像机的投影矩阵
    camera.updateProjectionMatrix();

    //   更新渲染器
    renderer.setSize(window.innerWidth, window.innerHeight);
    //   设置渲染器的像素比例
    renderer.setPixelRatio(window.devicePixelRatio);

  });

  //监听html中的世界
  eventHub.on("goMain", () => {
    console.log('收到html事假信息======> goMain');
    //开启轨道控制器
    controls.enabled = true;
    //关闭标点
    isTagPostion = false;
    //开启辉光
    isOpenLuminous = true;
    showAllObject(true);
    currentArr = mainArr;
    //关闭物体控制器
    objControls.visible = false;
    goMainCamera();
  });

  eventHub.on("tagPostion", () => {
    console.log('收到html事假信息======> tagPostion');
    tagPostion();
  });
});


</script>

<style>
* {
  margin: 0;
  padding: 0;
}

.container {
  height: 100vh;
  width: 100vw;
  background-color: #f0f0f0;
  z-index: 0;
}
</style>
